import Set from "../set/Set";
import Collection from "../core/Collection";
import Obj from "../core/Obj";

/**
 * 将键映射到值的对象。Map不能包含重复的键；每个键最多可以映射到一个值。
 *
 * Map接口提供了三个集合视图，允许将映射的内容视为一组键、一组值或一组键值映射。映射的顺序定义为地图集合视图上的迭代器返回其元素的顺序。
 *
 * 注意：如果将可变对象用作键，则必须非常小心。如果对象的某些属性在发生变更后导致{@link Obj#equalsTo}的结果产生了变化，Map将无法对其变换
 * 进行感知，因此仍存在一定的情况导致出现重复键（即在传入不同的元素后将元素的属性进行修改导致元素出现相等的情况）。
 *
 * @param K 存入地图的键类型
 * @param V 存入地图的值类型
 * @see Entry
 * @version 1.0
 */
export default interface Map<K, V> extends Iterable<Entry<K, V>>, Obj {

  /**
   * 返回此映射中的键值映射数。
   *
   * @return {number} 返回此映射中的键值映射数
   * @version 1.0
   */
  size(): number;

  /**
   * 返回此映射的容量。
   *
   * @return {number} 返回此映射的容量
   * @version 1.0
   */
  capacity(): number;

  /**
   * 返回此映射是否为空。
   *
   * @return {boolean} 如果此映射不包含键值映射，则返回 true
   * @version 1.0
   */
  isEmpty(): boolean;

  /**
   * 返回此映射是否已满。
   *
   * @return {boolean} 如果此映射已满，则返回 true
   * @version 1.0
   */
  isFull(): boolean;

  /**
   * 如果此映射包含指定键的映射，则返回 true。（最多可以有一个这样的映射。）
   *
   * @param key 要测试的键
   * @return {boolean} 如果存在相同的键，则返回 true
   * @version 1.0
   */
  containsKey(key: K): boolean;

  /**
   * 如果此映射包含指定值的映射，则返回 true。
   *
   * @param value 要测试的值
   * @return {boolean} 如果存在相同的值，则返回 true
   * @version 1.0
   */
  containsValue(value: V): boolean;

  /**
   * 返回指定键映射到的值，如果此映射不包含键的映射，则返回 undefined。（最多可以有一个这样的映射。）
   *
   * @param key 要查找的键
   * @return {V | undefined} 查找到的对应的值。如果没有对应的映射，则返回undefined
   * @version 1.0
   */
  get(key: K): V | undefined;

  /**
   * 将指定值与此映射中的指定键相关联。
   *
   * 如果映射先前包含键的映射，则旧值将替换为指定值。
   *
   * @param key 需要被管理的键
   * @param value 需要被管理那的值
   * @return {V | undefined} 如果已经存在该键，则返回旧值。如果不存在，则返回undefined
   * @throws {UnsupportedOperationException} put方法不被支持
   * @throws {FullCapacityException} 这个映射满了
   * @version 1.0
   */
  put(key: K, value: V): V | undefined;

  /**
   * 从此映射中删除指定键的映射（如果存在）。（地图最多可以包含一个这样的映射。）
   *
   * 返回此映射先前与键关联的值，如果映射不包含键的映射，则返回 undefined。
   *
   * @param key 需要被删除的键
   * @return {V | undefined} 如果指定的键存在，则返回被删除的映射的值。如果不存在，则返回undefined
   * @throws {UnsupportedOperationException} remove方法不被支持
   * @version 1.0
   */
  remove(key: K): V | undefined;

  /**
   * 清空这个映射。
   *
   * @throws {UnsupportedOperationException} clear方法不被支持
   * @version 1.0
   */
  clear(): void;

  /**
   * 返回此映射中包含的键的{@link Set}视图。该视图中不存在重复元素。
   *
   * 该集合由映射支持，因此对映射的更改会反映在该集合中，反之亦然。
   *
   * 如果在对集合进行迭代的同时修改了映射，则迭代的结果将随之发生变化的。
   *
   * @return {Set<K>} 一个包含了映射中所有键的集合
   * @see Set
   * @version 1.0
   */
  keySet(): Set<K>;

  /**
   * 返回此映射中包含的值的{@link Collection}视图。
   *
   * 该集合由映射支持，因此对映射的更改会反映在该集合中，反之亦然。
   *
   * 如果在对集合进行迭代的同时修改了映射，则迭代的结果将随之发生变化的。
   *
   * @return {Collection<K>} 一个包含了映射中所有值的集合
   * @see Collection
   * @version 1.0
   */
  values(): Collection<V>;

  /**
   * 返回此映射中包含的完整键值对的{@link Set}视图。
   *
   * 该集合由映射支持，因此对映射的更改会反映在该集合中，反之亦然。
   *
   * 如果在对集合进行迭代的同时修改了映射，则迭代的结果将随之发生变化的。
   *
   * @return {Set<K>} 一个包含了映射中所有值的集合
   * @see Set
   * @version 1.0
   */
  entrySet(): Set<Entry<K, V>>;

  /**
   * 返回指定键映射到的值，如果此映射不包含键的映射，则返回defaultValue。
   *
   * @param key 要查找的键
   * @param defaultValue 当查找不到时返回的默认值
   * @return {V} 返回指定键映射到的值，如果此映射不包含键的映射，则返回defaultValue
   * @version 1.0
   */
  getOrDefault(key: K, defaultValue: V): V;

  /**
   * 对此映射中的每一个键值对执行给定的操作，直到处理完所有条目或该操作引发异常。
   *
   * @param forEachFunc 对每一个键值对执行的操作
   * @version 1.0
   */
  forEach(forEachFunc: (key: K, value: V) => void): void;

  /**
   * 如果指定的键尚未与值关联，则将其与给定值关联，否则放弃。
   *
   * @param key 需要关联的键
   * @param value 需要关联的值
   * @throws {UnsupportedOperationException} putIfAbsent方法不被支持
   * @throws {FullCapacityException} 映射已经满了
   * @version 1.0
   */
  putIfAbsent(key: K, value: V): void;

  /**
   * 增加此映射的容量使其可以容纳更多的元素。
   *
   * 给出的容量必须比现有的容量更大，否则将会抛出{@link IllegalArgumentException}。当容量被设定为-1时，表示此映射容量无穷大，之后将不能再增
   * 加容量，也将不再判断容量是否充满。
   *
   * @param capacity 新的容量
   * @throws {IllegalArgumentException} 新的容量比当前容量小或容量已无法增长
   * @version 1.0
   */
  grow(capacity: number): void;
}

/**
 * 一个映射条目（键值对）。
 *
 * {@link Map#entrySet}方法返回地图的集合视图，其元素属于此类。
 *
 * @param K 存入地图的键类型
 * @param V 存入地图的值类型
 * @see Map
 * @version 1.0
 */
export interface Entry<K, V> extends Obj {

  /**
   * 返回与此条目的键。
   *
   * @return {K} 返回与此条目的键
   * @version 1.0
   */
  getKey(): K;

  /**
   * 返回此条目的值。
   *
   * 若此条目已经在映射中被删除，则返回undefined。
   *
   * @return {V | undefined} 此条目的值。若此条目已经被删除，则返回undefined
   * @version 1.0
   */
  getValue(): V | undefined;

  /**
   * 用指定的值替换与此条目对应的值，并返回原本的值。
   *
   * 如果映射已从映射中删除，则此调用将不产生任何作用（因为在原映射中已不再有此映射）。
   *
   * @param value 需要关联的新值
   * @return {V | undefined} 此条目中的旧值。若此条目已经被删除，则返回undefined
   * @throws {UnsupportedOperationException} 此映射对应的Map中的put方法不被支持
   * @version 1.0
   */
  setValue(value: V): V | undefined;
}
